<!-- 这个图片剪裁插件，兼容ios与安卓 -->

<template>
  <transition name="showWindow">
    <div
      id="clip_container"
      v-if="showCroper"
      class="container"
    >
      <header class="je-header">
        <div
          @tap.stop.prevent="handleCancel"
          class="back-btn mui-action-back"
        >
          取消
        </div>
        <div class="title">
          裁剪
        </div>
        <div
          @tap="crop"
          class="extra"
        >
          确定
        </div>
      </header>

      <div>
        <img
          id="clip_image"
          :src="originUrl"
        >
      </div>
    </div>
  </transition>
</template>

<script>

import Cropper from 'cropperjs';

export default {
  name: 'ImgCroper',
  props: {

    // 定义的宽高比

    widthRate: {

      type: Number,

      default: 1,

    },

    // 定义的宽高比

    heightRate: {

      type: Number,

      default: 1,

    },
    picValue: {

      type: Boolean,

      default() {
        return '';
      },

    },
    showCroper: {

      type: Boolean,

      default: false,

    },
  },

  data() {
    return {
      preview: null,
      resultObj: {},
      options: {},
      originUrl: '',
      cropper: {},
    };
  },
  watch: {
    showCroper(nv, ov) {
      if (nv) {
        this.$nextTick(() => {
          this.preview = document.getElementById('clip_image');
          // 调用初始化方法
          this.initilize({
            aspectWithRatio: Number(this.widthRate),
            aspectHeightRatio: Number(this.heightRate),
          });
          // 调用方法转成url格式
          this.originUrl = this.picValue;
          // 每次替换图片要重新得到新的url
          if (this.cropper) {
            this.cropper.replace(this.originUrl);
          }
        });
      }
    },
  },
  mounted() {
    Waves.init();
  },
  methods: {

    initilize(opt) {
      const self = this;
      this.options = opt;
      // 初始化裁剪对象
      this.cropper = new Cropper(this.preview, {

        aspectRatio: opt.aspectWithRatio / opt.aspectHeightRatio,

        // aspectRatio: 1/1,

        autoCropArea: opt.autoCropArea || 0.8,

        viewMode: 2,

        guides: true,

        cropBoxResizable: true, // 是否通过拖动来调整剪裁框的大小

        cropBoxMovable: true, // 是否通过拖拽来移动剪裁框。

        dragCrop: false,

        dragMode: 'move', // ‘crop’: 可以产生一个新的裁剪框3 ‘move’: 只可以移动3 ‘none’: 什么也不处理

        center: true,

        // zoomable: true, // 是否允许放大图像。

        zoomOnTouch: true, // 是否可以通过拖动触摸来放大图像。

        scalable: true,

        // minCropBoxHeight: 750,

        // minCropBoxWidth: 750,

        background: false,

        checkOrientation: true,

        checkCrossOrigin: true,

        zoomable: false,

        zoomOnWheel: false,

        // center: false,

        toggleDragModeOnDblclick: false,

        ready() {
          // console.log(self.cropper.rotate(90))

          if (opt.aspectRatio == 'Free') {
            const { cropBox } = self.cropper;

            cropBox.querySelector('span.cropper-view-box').style.outline = 'none';

            self.cropper.disable();
          }
        },

      });
    },

    // 初始化一些函数绑定
    handleCancel() {
      Waves.attach('.back-btn');
      this.showCroper = false;
      this.$emit('hideClip');
    },

    // 点击确定进行裁剪

    crop() {
      Waves.attach('.extra');
      const self = this;
      const image = new Image();
      let croppedCanvas;
      let roundedCanvas;
      // Crop
      JE.showWaiting('裁剪中...', true);
      setTimeout(() => {
        croppedCanvas = self.cropper.getCroppedCanvas();
        // Round
        roundedCanvas = self.getRoundedCanvas(croppedCanvas);
        const imgData = roundedCanvas.toDataURL();
        JE.closeWaiting();
        image.src = imgData;
        // self.postImg(imgData);
        // 判断图片是否大于100k,不大于直接上传，反之压缩
        if (imgData.length < (100 * 1024)) {
          // 图片上传
          self.postImg(imgData);
        } else {
          image.onload = () => {
            // 压缩处理
            const data = self.compress(image, self.Orientation);
            // 图片上传
            self.postImg(data);
          };
        }
      }, 20);
    },

    // 获取裁剪图片资源

    getRoundedCanvas(sourceCanvas) {
      const canvas = document.createElement('canvas');

      const context = canvas.getContext('2d');

      const { width } = sourceCanvas;

      const { height } = sourceCanvas;

      canvas.width = width;

      canvas.height = height;

      context.imageSmoothingEnabled = true;

      context.drawImage(sourceCanvas, 0, 0, width, height);

      context.globalCompositeOperation = 'destination-in';

      context.beginPath();

      context.rect(0, 0, width, height);

      context.fill();

      return canvas;
    },

    // 图片上传

    postImg(imageData) {
      this.$emit('upImg', imageData);
    },

    // 图片旋转

    rotateImg(img, direction, canvas) {
      // 最小与最大旋转方向，图片旋转4次后回到原方向

      const min_step = 0;

      const max_step = 3;

      if (img == null) return;

      // img的高度和宽度不能在img元素隐藏后获取，否则会出错

      const { height } = img;

      const { width } = img;

      let step = 2;

      if (step == null) {
        step = min_step;
      }

      if (direction == 'right') {
        step++;

        // 旋转到原位置，即超过最大值

        step > max_step && (step = min_step);
      } else {
        step--;

        step < min_step && (step = max_step);
      }

      // 旋转角度以弧度值为参数

      const degree = step * 90 * Math.PI / 180;

      const ctx = canvas.getContext('2d');

      switch (step) {
        case 0:

          canvas.width = width;

          canvas.height = height;

          ctx.drawImage(img, 0, 0);

          break;

        case 1:

          canvas.width = height;

          canvas.height = width;

          ctx.rotate(degree);

          ctx.drawImage(img, 0, -height);

          break;

        case 2:

          canvas.width = width;

          canvas.height = height;

          ctx.rotate(degree);

          ctx.drawImage(img, -width, -height);

          break;

        case 3:

          canvas.width = height;

          canvas.height = width;

          ctx.rotate(degree);

          ctx.drawImage(img, -width, 0);

          break;
        default:
          break;
      }
    },

    // 图片压缩

    compress(img, Orientation) {
      const canvas = document.createElement('canvas');

      const ctx = canvas.getContext('2d');

      // 瓦片canvas

      const tCanvas = document.createElement('canvas');

      const tctx = tCanvas.getContext('2d');

      const initSize = img.src.length;

      let { width } = img;

      let { height } = img;


      // 如果图片大于四百万像素，计算压缩比并将大小压至400万以下

      let ratio;

      if ((ratio = width * height / 4000000) > 1) {
        console.log('大于400万像素');

        ratio = Math.sqrt(ratio);

        width /= ratio;

        height /= ratio;
      } else {
        ratio = 1;
      }

      canvas.width = width;

      canvas.height = height;

      //        铺底色

      ctx.fillStyle = '#fff';

      ctx.fillRect(0, 0, canvas.width, canvas.height);

      // 如果图片像素大于100万则使用瓦片绘制

      let count;

      if ((count = width * height / 1000000) > 1) {
        count = ~~(Math.sqrt(count) + 1); // 计算要分成多少块瓦片

        //            计算每块瓦片的宽和高

        const nw = ~~(width / count);

        const nh = ~~(height / count);

        tCanvas.width = nw;

        tCanvas.height = nh;

        for (let i = 0; i < count; i++) {
          for (let j = 0; j < count; j++) {
            tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh);

            ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh);
          }
        }
      } else {
        ctx.drawImage(img, 0, 0, width, height);
      }

      // 修复ios上传图片的时候 被旋转的问题

      if (Orientation != '' && Orientation != 1) {
        switch (Orientation) {
          case 6: // 需要顺时针（向左）90度旋转

            this.rotateImg(img, 'left', canvas);

            break;

          case 8: // 需要逆时针（向右）90度旋转

            this.rotateImg(img, 'right', canvas);

            break;

          case 3: // 需要180度旋转

            this.rotateImg(img, 'right', canvas); // 转两次

            this.rotateImg(img, 'right', canvas);

            break;
          default:
            break;
        }
      }

      // 进行最小压缩

      // let ndata = canvas.toDataURL( 'image/jpeg' , 0.1);

      const ndata = canvas.toDataURL('image/jpeg', 0.1);

      console.log(`压缩前：${initSize}`);

      console.log(`压缩后：${ndata.length}`);

      console.log(`压缩率：${~~(100 * (initSize - ndata.length) / initSize)}%`);

      tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0;


      return ndata;
    },

  },

};

</script>

<style lang="less">
.showWindow-enter-active {
  opacity: 1;
  transition: all 1s;
  background: rgba(7, 17, 27, 0.8);
}
.showWindow-leave-active {
  opacity: 0;
  transition: all 1s;
  background: rgba(7, 17, 27, 0);
}
.showWindow-enter {
  opacity: 0;
  background: rgba(7, 17, 27, 0);
}
.showWindow-leave {
  opacity: 1;
  background: rgba(7, 17, 27, 0.8);
}

header.je-header:not(.main-title) > * {
  flex: inherit;
}
header.je-header .title {
  flex: 1;
}

* {
  margin: 0;

  padding: 0;
}

#clip_container.container {
  z-index: 99999;

  position: fixed;

  padding-top: 120px;

  left: 0;

  top: 0;

  right: 0;

  bottom: 0;

  background: rgba(0, 0, 0, 1);
}

#clip_container.container > div {
  position: absolute;

  width: 100%;

  height: 100%;

  top: 50%;

  left: 50%;

  -webkit-transform: translate(-50%, -50%);

  transform: translate(-50%, -50%);
}

#clip_image {
  max-width: 100%;
}

.cropper-container {
  font-size: 0;

  line-height: 0;

  position: relative;

  -webkit-user-select: none;

  -moz-user-select: none;

  -ms-user-select: none;

  user-select: none;

  direction: ltr;

  -ms-touch-action: none;

  touch-action: none;
}

.cropper-container img {
  /* Avoid margin top issue (Occur only when margin-top <= -height) */

  display: block;

  min-width: 0 !important;

  max-width: none !important;

  min-height: 0 !important;

  max-height: none !important;

  width: 100%;

  height: 100%;

  image-orientation: 0deg;
}

.cropper-wrap-box,
.cropper-canvas,
.cropper-drag-box,
.cropper-crop-box,
.cropper-modal {
  position: absolute;

  top: 0;

  right: 0;

  bottom: 0;

  left: 0;
}

.cropper-wrap-box {
  overflow: hidden;
}

.cropper-drag-box {
  opacity: 0;

  background-color: #fff;
}

.cropper-modal {
  opacity: 0.5;

  background-color: #000;
}

.cropper-view-box {
  display: block;

  overflow: hidden;

  width: 100%;

  height: 100%;

  outline: 1px solid #39f;

  outline-color: rgba(51, 153, 255, 0.75);
}

.cropper-dashed {
  position: absolute;

  display: block;

  opacity: 0.5;

  border: 0 dashed #eee;
}

.cropper-dashed.dashed-h {
  top: 33.33333%;

  left: 0;

  width: 100%;

  height: 33.33333%;

  border-top-width: 1px;

  border-bottom-width: 1px;
}

.cropper-dashed.dashed-v {
  top: 0;

  left: 33.33333%;

  width: 33.33333%;

  height: 100%;

  border-right-width: 1px;

  border-left-width: 1px;
}

.cropper-center {
  position: absolute;

  top: 50%;

  left: 50%;

  display: block;

  width: 0;

  height: 0;

  opacity: 0.75;
}

.cropper-center:before,
.cropper-center:after {
  position: absolute;

  display: block;

  content: " ";

  background-color: #eee;
}

.cropper-center:before {
  top: 0;

  left: -3px;

  width: 7px;

  height: 1px;
}

.cropper-center:after {
  top: -3px;

  left: 0;

  width: 1px;

  height: 7px;
}

.cropper-face,
.cropper-line,
.cropper-point {
  position: absolute;

  display: block;

  width: 100%;

  height: 100%;

  opacity: 0.1;
}

.cropper-face {
  top: 0;

  left: 0;

  background-color: #fff;
}

.cropper-line {
  background-color: #39f;
}

.cropper-line.line-e {
  top: 0;

  right: -3px;

  width: 5px;

  cursor: e-resize;
}

.cropper-line.line-n {
  top: -3px;

  left: 0;

  height: 5px;

  cursor: n-resize;
}

.cropper-line.line-w {
  top: 0;

  left: -3px;

  width: 5px;

  cursor: w-resize;
}

.cropper-line.line-s {
  bottom: -3px;

  left: 0;

  height: 5px;

  cursor: s-resize;
}

.cropper-point {
  width: 5px;

  height: 5px;

  opacity: 0.75;

  background-color: #39f;
}

.cropper-point.point-e {
  top: 50%;

  right: -3px;

  margin-top: -3px;

  cursor: e-resize;
}

.cropper-point.point-n {
  top: -3px;

  left: 50%;

  margin-left: -3px;

  cursor: n-resize;
}

.cropper-point.point-w {
  top: 50%;

  left: -3px;

  margin-top: -3px;

  cursor: w-resize;
}

.cropper-point.point-s {
  bottom: -3px;

  left: 50%;

  margin-left: -3px;

  cursor: s-resize;
}

.cropper-point.point-ne {
  top: -3px;

  right: -3px;

  cursor: ne-resize;
}

.cropper-point.point-nw {
  top: -3px;

  left: -3px;

  cursor: nw-resize;
}

.cropper-point.point-sw {
  bottom: -3px;

  left: -3px;

  cursor: sw-resize;
}

.cropper-point.point-se {
  right: -3px;

  bottom: -3px;

  width: 40px;

  height: 40px;

  cursor: se-resize;

  opacity: 1;
}

@media (min-width: 768px) {
  .cropper-point.point-se {
    width: 15px;

    height: 15px;
  }
}

@media (min-width: 992px) {
  .cropper-point.point-se {
    width: 10px;

    height: 10px;
  }
}

@media (min-width: 1200px) {
  .cropper-point.point-se {
    width: 5px;

    height: 5px;

    opacity: 0.75;
  }
}

.cropper-point.point-se:before {
  position: absolute;

  right: -50%;

  bottom: -50%;

  display: block;

  width: 200%;

  height: 200%;

  content: " ";

  opacity: 0;

  background-color: #39f;
}

.cropper-invisible {
  opacity: 0;
}

.cropper-bg {
  background-image: url("");
}

.cropper-hide {
  position: absolute;
  display: block;
  width: 0;
  height: 0;
}

.cropper-hidden {
  display: none !important;
}

.cropper-move {
  cursor: move;
}

.cropper-crop {
  cursor: crosshair;
}

.cropper-disabled .cropper-drag-box,
.cropper-disabled .cropper-face,
.cropper-disabled .cropper-line,
.cropper-disabled .cropper-point {
  cursor: not-allowed;
}
</style>
